package hapi.math;

class MathUtil {
	
	public inline static var kPI = Math.PI;
	public inline static var k2PI = kPI*2.0;
	public inline static var kPIOver2 = kPI / 2.0;
	public inline static var k1OverPI = 1 / kPI;
	public inline static var k1Over2PI = 1 / k2PI;
	public inline static var k180OverPI = 180 / kPI;
	public inline static var kPIOver180 = kPI / 180;
	
	#if neko
	public static inline var SMALLEST_POSSIBLE_FLOAT = 0.0000000000009;
	#else 
	public static inline var SMALLEST_POSSIBLE_FLOAT = 5e-324;
	#end
	
	public static inline function wrapPI( theta ):Float {
		if (theta == k2PI) 
			return 0.0;
		else{
			theta += kPI;
			theta -= Math.floor( theta * k1Over2PI ) * k2PI;
			theta -= kPI;
			return theta;
		}
	}
	
	public static function safeAcos( theta:Float ):Float {
		if ( theta <= -1 )
			return -kPI;
		else if( theta >= 1 )
			return 0;
		
		return Math.acos( theta );
	}
	
	public inline static function sgn( x:Float ):Int {
		return if ( x < 0 ) -1 else 1;
	}
	
	public inline static function radToDeg( rad:Float ):Float {
		return k180OverPI*rad;
	}
	
	public inline static function degToRad( deg:Float ):Float {
		return kPIOver180*deg;
	}
	
	public static inline function minimaizeAngle( theta:Float ):Float {
		theta = wrapPI(theta);
		if ( theta < -kPI) theta =  k2PI + theta;
		else if ( theta > kPI) theta =  k2PI - theta;
		if ( theta == -kPI ) theta = kPI;
		return theta;
	}
	
	public static function angularDelta( fromAlfa:Float, toBeta:Float ):Float {
		var result = toBeta - fromAlfa;
		var abs = Math.abs( result );
		if ( abs > kPI ) result = sgn(-result) * (k2PI - abs);
		if ( result == -kPI ) result = kPI;
		if ( result >= k2PI ) result %= k2PI;
		return result;
	}
	
	public static inline function roundTo( value:Float, decimalPlaces:Int ):Float {
		var mult = Math.pow(10, decimalPlaces);
		return Math.floor(value * mult) / mult;
	}
	
	public static inline function floatEquals( a:Float, b:Float, ?epsilon:Float = SMALLEST_POSSIBLE_FLOAT):Bool {
		return if ( a == b )
			true;
		else if ( a > b )
			a - b <= epsilon;
		else
			b - a <= epsilon;
	}
}
